use std::alloc::AllocError;
use std::fmt::{Debug, Display, Formatter};
use std::io::ErrorKind;

#[derive(Debug)]
pub enum Error {
    AllocErr(String),

    EntryLineProtocolErr(String),

    StorageErr(String),

    ExecutionErr(String),

    NetworkErr(String),
}

/// 内存分配出现错误
const CODE_ALLOC_ERROR: u32 = 100_000;

/// Entry Line Protocol 解析错误
const CODE_ENTRY_LINE_PROTOCOL_ERROR: u32 = 100_100;
const STORAGE_ERROR: u32 = 100_200;

const EXECUTION_ERROR: u32 = 100_300;

const NETWORK_ERROR: u32 = 100_400;

impl From<AllocError> for Error {
    #[inline]
    fn from(e: AllocError) -> Self {
        Error::AllocErr(e.to_string())
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        Debug::fmt(self, f)
    }
}

impl std::error::Error for Error {
}

impl Error {

    pub fn code(&self) -> u32 {
        match self {
            Error::AllocErr(_) => CODE_ALLOC_ERROR,
            Error::EntryLineProtocolErr(_) => CODE_ENTRY_LINE_PROTOCOL_ERROR,
            Error::StorageErr(_) => STORAGE_ERROR,
            Error::ExecutionErr(_) => EXECUTION_ERROR,
            Error::NetworkErr(_) => NETWORK_ERROR
        }
    }

    pub fn to_io_error(self) -> std::io::Error {
        std::io::Error::new(ErrorKind::Other, self)
    }

}